package miniodeploylogic

import (
	"context"
	"errors"
	"fmt"
	"github.com/zeromicro/go-zero/core/logx"
	"strings"
	"sync"
	"time"
	"yunzhan/common/models"
	utils "yunzhan/common/utils"
	"yunzhan/rpc-server/internal/svc"
	agent "yunzhan/rpc-server/pb"
)

type DeployMinIOSingleNodeLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewDeployMinIOSingleNodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeployMinIOSingleNodeLogic {
	return &DeployMinIOSingleNodeLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

// DeployMinIOSingleNode 单机部署
func (l *DeployMinIOSingleNodeLogic) DeployMinIOSingleNode(in *agent.DeployMinIORequest) (*agent.DeployResponse, error) {
	if in.NodeInfo == nil {
		return &agent.DeployResponse{
			Code:    500,
			Message: "未配置节点信息, 无法执行MinIO单机部署",
		}, errors.New("未配置节点信息, 无法执行MinIO单机部署")
	}

	resp := &agent.DeployResponse{
		Code:    200,
		Message: fmt.Sprintf("请求已接收，正在部署 %s 到节点 %s", in.ConfigInfo.ComponentName, in.NodeInfo.Host),
	}

	go l.startDeployment(in)

	return resp, nil
}

func (l *DeployMinIOSingleNodeLogic) startDeployment(in *agent.DeployMinIORequest) {

	var wg sync.WaitGroup

	wg.Add(1)
	go func() {
		defer wg.Done()

		// 创建 LogManager 实例
		logManager := models.NewLogManager(100, fmt.Sprintf("http://%s:%d", l.svcCtx.Config.RestServices["apiServer"].RestConf.Host, l.svcCtx.Config.RestServices["apiServer"].RestConf.Port))
		defer logManager.Close()

		flushInterval := 5 * time.Second // 刷新间隔
		maxBatchSize := 100              // 最大批量大小
		retryDelay := 2 * time.Second    // 重试延迟
		maxRetries := 3                  // 最大重试次数

		// 创建 ComponentInfoManager 实例
		componentInfoManager := models.NewComponentInfoManager(
			1000,
			fmt.Sprintf("http://%s:%d", l.svcCtx.Config.RestServices["apiServer"].RestConf.Host, l.svcCtx.Config.RestServices["apiServer"].RestConf.Port),
			flushInterval,
			maxBatchSize,
			retryDelay,
			maxRetries)
		defer componentInfoManager.Close()
		packageDirectory := in.ConfigInfo.PackagePath
		rtrimDir := utils.Rtrim(packageDirectory, "/")
		minioVersion := in.ConfigInfo.ComponentName
		installPath := utils.Rtrim(in.ConfigInfo.InstallPath, "/")
		baseInfo := fmt.Sprintf("安装包存放目录: %s, MinIO version: %s, MinIO 安装目录: %s", rtrimDir, minioVersion, installPath)
		step := 1
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "INFO", baseInfo, "MinIO", "Server")

		checkPathCommand := fmt.Sprintf(`
if [ ! -d "%s" ]; then
   sudo mkdir -p "%s"
fi
`, installPath, installPath)

		step++
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "start", "执行组件安装路径检查...", "MinIO", "Server")
		output, err := utils.ExecCommand(checkPathCommand)
		if err != nil {
			message := fmt.Sprintf("检查组件安装路径异常: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "failure", message, "MinIO", "Server")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "success", "检查组件安装路径完成", "MinIO", "Server")

		step++
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "start", "解压安装包...", "MinIO", "Server")
		tarCommand := fmt.Sprintf("sudo tar -xzf %s/%s -C %s", rtrimDir, minioVersion, installPath)
		output, err = utils.ExecCommand(tarCommand)
		if err != nil {
			message := fmt.Sprintf("解压安装包异常: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "failure", message, "MinIO", "Server")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "success", "解压安装包完成", "MinIO", "Server")

		minioHome := utils.Rtrim(minioVersion, ".tar.gz")
		home := fmt.Sprintf("%s/%s", installPath, minioHome)

		step++
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "start", "修改组件所属用户组...", "MinIO", "Server")
		chownCommand := fmt.Sprintf("sudo chown -R %s:%s %s", in.NodeInfo.Username, in.NodeInfo.Username, home)
		output, err = utils.ExecCommand(chownCommand)
		if err != nil {
			message := fmt.Sprintf("修改组件所属用户组异常: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "failure", message, "MinIO", "Server")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "success", "修改组件所属用户组完成", "MinIO", "Server")

		step++
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "start", "配置minio.conf文件...", "MinIO", "Server")
		volumes := strings.Join(in.MinIOConfig.MinioVolumes[0].Volumes, ",")
		configCommand := fmt.Sprintf("sed -i '/^\\s*#\\?\\s*MINIO_ROOT_USER=/c\\MINIO_ROOT_USER=%s' %s/minio.conf", in.MinIOConfig.MinioRootUser, home)
		configCommand += fmt.Sprintf(" && sed -i '/^\\s*#\\?\\s*MINIO_ROOT_PASSWORD=/c\\MINIO_ROOT_PASSWORD=%s' %s/minio.conf", in.MinIOConfig.MinioRootPassword, home)
		configCommand += fmt.Sprintf(" && sed -i '/^\\s*#\\?\\s*MINIO_VOLUMES=/c\\MINIO_VOLUMES=\"%s\"' %s/minio.conf", volumes, home)
		configCommand += fmt.Sprintf(" && sed -i '/^\\s*#\\?\\s*MINIO_OPTS=/c\\MINIO_OPTS=\"--address %s --console-address %s\"' %s/minio.conf", in.MinIOConfig.ListeningAddress, in.MinIOConfig.ConsoleAddress, home)
		output, err = utils.ExecCommand(configCommand)
		if err != nil {
			message := fmt.Sprintf("配置minio.conf文件异常: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "failure", message, "MinIO", "Server")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "success", "配置minio.conf文件完成", "MinIO", "Server")

		minioServiceFile := fmt.Sprintf(`[Unit]
Description=MinIO
Documentation=https://minio.org.cn/docs/minio/linux/index_node01.html
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=%s/minio

[Service]
User=%s
Group=%s
ProtectProc=invisible

WorkingDirectory=%s
EnvironmentFile=-%s/minio.conf
ExecStartPre=/bin/bash -c "if [ -z \"${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in %s/minio.conf\"; exit 1; fi"
ExecStart=%s/minio server $MINIO_OPTS $MINIO_VOLUMES

# Redirect stdout and stderr to log file
StandardOutput=append:%s/logs/minio.log
StandardError=append:%s/logs/minio.log

# Let systemd restart this service always
Restart=always

# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=655355

# Specifies the maximum number of threads this process can create
TasksMax=infinity

# Disable timeout logic and wait until process is stopped
TimeoutStopSec=infinity
SendSIGKILL=no

[Install]
WantedBy=multi-user.target`, home, in.NodeInfo.Username, in.NodeInfo.Username, home, home, home, home, home, home)
		step++
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "start", "创建minio.service文件...", "MinIO", "Server")
		writeServiceFileCommand := fmt.Sprintf("echo '%s' | sudo tee /etc/systemd/system/minio.service", minioServiceFile)
		output, err = utils.ExecCommand(writeServiceFileCommand)
		if err != nil {
			message := fmt.Sprintf("创建 minio.service 文件异常: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "failure", message, "MinIO", "Server")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "success", "创建minio.service文件完成", "MinIO", "Server")

		step++
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "start", "启动MinIO服务...", "MinIO", "Server")
		reloadSystemdCommand := fmt.Sprintf("sudo systemctl daemon-reload && sudo systemctl enable minio.service --now")
		output, err = utils.ExecCommand(reloadSystemdCommand)
		if err != nil {
			message := fmt.Sprintf("启动MinIO服务异常: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "failure", message, "MinIO", "Server")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "success", "启动MinIO服务完成", "MinIO", "Server")

		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "start", "等待MinIO服务完全启动", "MinIO", "Server")

		time.Sleep(3 * time.Second)
		step++
		statusCommand := "sudo systemctl is-active minio.service"
		output, err = utils.ExecCommand(statusCommand)
		if err != nil || strings.TrimSpace(output) != "active" {
			message := fmt.Sprintf("MinIO启动后未正常运行: %v, output: %s", err, output)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "failure", message, "MinIO", "Server")
			return
		}
		logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "success", "MinIO部署成功", "MinIO", "Server")

		currentIP, currentIPErr := utils.GetCurrentInternalIP()
		if err != nil {
			message := fmt.Sprintf("%s: 无法获取当前主机IP: %v", in.NodeInfo.Host, currentIPErr)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "failure", message, "MinIO", "Server")
			return
		}
		currentHost, currentHostErr := utils.GetCurrentHostname()
		if err != nil {
			message := fmt.Sprintf("%s: 无法获取当前主机名: %v", in.NodeInfo.Host, currentHostErr)
			logManager.SendLog(in.ClusterID, in.NodeInfo.Host, step, "failure", message, "MinIO", "Server")
			return
		}

		minioInfo := &models.ComponentInfo{
			ClusterID:      in.ClusterID,
			ComponentName:  "MinIO",
			Version:        in.Version,
			NodeHost:       currentHost,
			NodeIP:         currentIP,
			ComponentRole:  "Server",
			HomePath:       home,
			DataStorageDir: strings.Join(in.MinIOConfig.MinioVolumes[0].Volumes, ","),
			Port:           in.MinIOConfig.ListeningAddress,
			Status:         true,
			AdditionalInfo: fmt.Sprintf("config_file=%s/minio.conf", home),
		}

		componentInfoManager.SendComponentInfo(minioInfo)

	}()

	wg.Wait()

}
